Skip to content

Refactor pattern shaders to use OpenMPT numeric note encoding#112

Merged
ford442 merged 3 commits intomainfrom
claude/audit-module-format-compliance-QesFv
Mar 20, 2026
Merged

Refactor pattern shaders to use OpenMPT numeric note encoding#112
ford442 merged 3 commits intomainfrom
claude/audit-module-format-compliance-QesFv

Conversation

@ford442
Copy link
Copy Markdown
Owner

@ford442 ford442 commented Mar 20, 2026

Summary

Unified pattern shader implementations to use OpenMPT's numeric note encoding (1–120 for notes, 121 for OFF, 122–123 for CUT/FADE) instead of ASCII character parsing. This simplifies note detection logic and improves consistency across shader versions.

Key Changes

patternv0.42.wgsl (Major Rewrite)

  • Complete architectural redesign: Converted from full-screen fragment-only shader to single-pass vertex+fragment with per-cell instancing
  • Ring geometry: Implemented circular ring layout with 64 angular steps and per-channel rings
  • Note encoding: Replaced ASCII parsing with direct numeric note value checks (1–120 = notes, 121 = OFF, 122–123 = CUT/FADE)
  • Micro-LED indicators: Added three indicator LEDs per cell:
    • Blue (top-left): Note-on trigger state
    • Amber (top-right): Volume/expression command presence
    • Green (bottom-center): Effect command presence
  • Enhanced visuals: Added neon palette driven by beat phase, frosted surface shading, and improved playhead highlighting

patternv0.45.wgsl

  • Simplified pitch detection: Replaced complex ASCII character-to-semitone switch statement with direct numeric calculation: (note - 1) % 12
  • Unified note classification: Added explicit checks for note-off (121) and note-cut (122–123) states
  • Micro-LED system: Integrated blue note-on, amber volume, and green effect indicators matching v0.42 design
  • Improved color handling: Better separation of note-on, note-off, and note-cut visual states with distinct colors

patternv0.38.wgsl

  • Note encoding update: Changed note validation from (note > 0u) to (note > 0u) && (note <= 120u) to properly handle OpenMPT encoding
  • Note-off/cut detection: Added explicit checks for note-off (121) and note-cut (122–123) states
  • Indicator color correction: Changed top LED from cyan to amber for volume/expression indicator consistency

PatternDisplay.tsx

  • Shader selection logic: Updated circular layout detection to include v0.42 alongside existing circular shaders (v0.25, v0.26, v0.35, v0.37, v0.38, v0.45, v0.46)

Implementation Details

  • OpenMPT numeric encoding: note values 1–120 map to C-0 through B-9; special values 121 (OFF), 122 (CUT), 123 (FADE) indicate note commands
  • Pitch class calculation uses modulo 12 arithmetic: (note - 1) % 12 yields 0–11 for C through B
  • Micro-LED indicators provide visual feedback for note triggers, volume commands, and effects without cluttering the main cell display
  • Ring layout in v0.42 uses per-instance geometry with proper angular positioning and radial depth mapping

https://claude.ai/code/session_01K5XYz1JJ1ppmmfcCGPzz9w

claude added 3 commits March 20, 2026 20:33
…te-on/volume indicators

Audit findings and fixes:

1. v0.42.wgsl — complete rewrite (was full-screen quad, showed zero pattern data):
   - Convert to per-cell instancing (circular ring layout, 64-step arcs)
   - instanceIndex >= totalCells renders ring-grid background pass
   - instanceIndex < totalCells renders per-cell quads with note data
   - Add cells[] / channels[] / rowFlags bindings
   - Blue micro-LED (top-left): note-on indicator (lights when playhead hits)
   - Amber micro-LED (top-right): volume command indicator (volCmd > 0)
   - Green micro-LED (bottom): effect command indicator (effCmd > 0)
   - Red/orange tint for note-off (121) and note-cut (122/123)

2. v0.45.wgsl — fix critical note detection bug:
   - REMOVE ASCII range check (noteChar >= 65 && <= 122) which missed notes 1-64
     (roughly C-0 through E-4, including middle-C / C-4 = note 60)
   - FIX pitchClassFromPacked: replace ASCII switch table with correct numeric
     formula: (note - 1) % 12 (OpenMPT internal: note 1 = C-0, note 13 = C-1…)
   - Add note-off (121) and note-cut/fade (122/123) visual distinction
   - Add same three micro-LED indicators as v0.42

3. v0.38.wgsl — targeted fixes:
   - Fix hasNote: (note > 0u) → (note > 0u && note <= 120u) to exclude 121-123
   - Add isNoteOff/isNoteCut rendering in main LED (dim red / orange)
   - Change top LED from cyan to amber to consistently indicate volume/expression

4. PatternDisplay.tsx:
   - Add v0.42 to isHighPrec list (was using old standard packing, missing volCmd)
   - Add v0.42 to isCircularLayoutShader (affects bezel uniform scaling)

Format compliance note: libopenmpt returns OpenMPT internal note numbers (0-123)
directly. Shaders must use numeric comparisons, not ASCII character ranges.

https://claude.ai/code/session_01K5XYz1JJ1ppmmfcCGPzz9w
Critical fixes from shader visual audit:

1. v0.45.wgsl — Remove early discard clipping 30% of cells:
   - Line 221-223: Removed `if (!isCap) { discard; }` that clipped all cells outside frosted cap bounds
   - Replace with alpha masking via capEdge (smoothstep on SDF)
   - Allows all pattern cells to render with proper falloff at edges

2. v0.47.wgsl — Fix instrument byte unpacking:
   - Line 357: Changed `inst = in.packedA & 255u` → `(in.packedA >> 16) & 255u`
   - Was reading lowest byte (value field) instead of bits 16-23
   - Also fixed note check: ASCII A-G (65-71) → numeric 1-120 range
   - Now displays all notes correctly and brightness calculation works

3. v0.46.wgsl & v0.49.wgsl — Fix derivative undefined behavior:
   - Moved early `if (in.position.y > canvasH * 0.88) { discard; }` to AFTER playheadActivation computation
   - Early discard before fwidth() was called created non-uniform control flow
   - Could cause undefined behavior in derivative calculations
   - Now safe: discard only after all derivatives consumed

4. v0.45.wgsl — Verified playheadActivation scope:
   - Computed at line 240, used safely throughout at 255-309 ✓

Impact: v0.45/46/47/49 now render complete pattern data without clipping or missing notes.

https://claude.ai/code/session_01K5XYz1JJ1ppmmfcCGPzz9w
Prevent undefined buffer access in v0.47/48/49/50:

All circular layout shaders that access channels[in.channel] now include bounds checks
before array access. This prevents GPU crashes or silent data corruption when:
- padTopChannel is enabled (shifts music channels 1-32, adds dummy channel 0)
- numChannels array length doesn't match expected size

Pattern: Changed `let ch = channels[in.channel];` to:
```
var ch = ChannelState(0.0, 0.0, 0.0, 0u, 1000.0, 0u, 0.0, 0u);
if (in.channel < arrayLength(&channels)) {
  ch = channels[in.channel];
}
```

v0.45 and v0.39 already had correct bounds checks.
v0.46 is overlay-only and doesn't access channels[].

This fixes the CRITICAL undefined behavior identified in shader audit.

https://claude.ai/code/session_01K5XYz1JJ1ppmmfcCGPzz9w
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@ford442 ford442 merged commit 4e301cd into main Mar 20, 2026
2 checks passed
@ford442 ford442 deleted the claude/audit-module-format-compliance-QesFv branch March 20, 2026 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants